﻿using System;

public class Mapper021 : MapperDefault
{
    private int irq_counter;
    private int irq_enabled;
    private int irq_latch;
    private int[] regs = new int[9];

    public override void init(NES nes)
    {
        base.init(nes);
        this.reset();
    }

    public override void loadROM(ROM rom)
    {
        if (!rom.Valid)
        {
            Console.Out.WriteLine("VRC4: Invalid ROM! Unable to load.");
        }
        else
        {
            int num = rom.RomBankCount * 2;
            this.load8kRomBank(0, 0x8000);
            this.load8kRomBank(1, 0xa000);
            this.load8kRomBank(num - 2, 0xc000);
            this.load8kRomBank(num - 1, 0xe000);
            this.loadCHRROM();
            this.loadBatteryRam();
            base.nes.Cpu.requestIrq(2);
        }
    }

    public override void reset()
    {
        this.regs[0] = 0;
        this.regs[1] = 1;
        this.regs[2] = 2;
        this.regs[3] = 3;
        this.regs[4] = 4;
        this.regs[5] = 5;
        this.regs[6] = 6;
        this.regs[7] = 7;
        this.regs[8] = 0;
        this.irq_enabled = 0;
        this.irq_latch = 0;
        this.irq_counter = 0;
    }

    public override int syncH(int scanline)
    {
        if ((this.irq_enabled & 2) != 0)
        {
            if (this.irq_counter == 0)
            {
                this.irq_counter = this.irq_latch;
                this.irq_enabled = (this.irq_enabled & 1) * 3;
                return 3;
            }
            this.irq_counter++;
        }
        return 0;
    }

    public override void write(int address, short value_Renamed)
    {
        if (address < 0x8000)
        {
            base.write(address, value_Renamed);
            return;
        }
        int num = address & 0xf0cf;
        if (num <= 0xc0c0)
        {
            if (num <= 0xb040)
            {
                switch (num)
                {
                    case 0xb000:
                        this.regs[0] = (this.regs[0] & 240) | (value_Renamed & 15);
                        this.load1kVromBank(this.regs[0], 0);
                        return;

                    case 0xb001:
                    case 0xb004:
                        goto Label_02E8;

                    case 0xb002:
                    case 0xb040:
                        this.regs[0] = (this.regs[0] & 15) | ((value_Renamed & 15) << 4);
                        this.load1kVromBank(this.regs[0], 0);
                        return;

                    case 0xb003:
                    case 0xb006:
                        goto Label_0317;

                    case 0xb005:
                    case 0x9001:
                        return;

                    case 0xa000:
                        this.load8kRomBank(value_Renamed, 0xa000);
                        return;

                    case 0x9000:
                        value_Renamed = (short) (value_Renamed & 3);
                        if (value_Renamed != 0)
                        {
                            if (value_Renamed == 1)
                            {
                                base.nes.Ppu.Mirroring = 1;
                                return;
                            }
                            if (value_Renamed == 2)
                            {
                                base.nes.Ppu.Mirroring = 3;
                                return;
                            }
                            base.nes.Ppu.Mirroring = 4;
                            return;
                        }
                        base.nes.Ppu.Mirroring = 0;
                        return;

                    case 0x9002:
                    case 0x9080:
                        this.regs[8] = value_Renamed;
                        return;

                    case 0x8000:
                        if ((this.regs[8] & 2) != 0)
                        {
                            this.load8kRomBank(value_Renamed, 0xc000);
                            return;
                        }
                        this.load8kRomBank(value_Renamed, 0x8000);
                        return;
                }
                return;
            }
            if (num > 0xc006)
            {
                switch (num)
                {
                    case 0xc040:
                        goto Label_0374;

                    case 0xc080:
                        goto Label_03A2;

                    case 0xc0c0:
                        goto Label_03D1;
                }
                return;
            }
            if (num != 0xb080)
            {
                switch (num)
                {
                    case 0xc000:
                        this.regs[2] = (this.regs[2] & 240) | (value_Renamed & 15);
                        this.load1kVromBank(this.regs[2], 0x800);
                        return;

                    case 0xc001:
                    case 0xc004:
                        goto Label_03A2;

                    case 0xc002:
                        goto Label_0374;

                    case 0xc003:
                    case 0xc006:
                        goto Label_03D1;

                    case 0xc005:
                        return;

                    case 0xb0c0:
                        goto Label_0317;
                }
                return;
            }
        }
        else
        {
            if (num <= 0xe040)
            {
                switch (num)
                {
                    case 0xe000:
                        this.regs[6] = (this.regs[6] & 240) | (value_Renamed & 15);
                        this.load1kVromBank(this.regs[6], 0x1800);
                        return;

                    case 0xe001:
                    case 0xe004:
                        goto Label_0516;

                    case 0xe002:
                    case 0xe040:
                        this.regs[6] = (this.regs[6] & 15) | ((value_Renamed & 15) << 4);
                        this.load1kVromBank(this.regs[6], 0x1800);
                        return;

                    case 0xe003:
                    case 0xe006:
                        goto Label_0545;

                    case 0xe005:
                    case 0xd005:
                        return;

                    case 0xd0c0:
                    case 0xd003:
                    case 0xd006:
                        this.regs[5] = (this.regs[5] & 15) | ((value_Renamed & 15) << 4);
                        this.load1kVromBank(this.regs[5], 0x1400);
                        return;

                    case 0xd000:
                        this.regs[4] = (this.regs[4] & 240) | (value_Renamed & 15);
                        this.load1kVromBank(this.regs[4], 0x1000);
                        return;

                    case 0xd001:
                    case 0xd004:
                    case 0xd080:
                        this.regs[5] = (this.regs[5] & 240) | (value_Renamed & 15);
                        this.load1kVromBank(this.regs[5], 0x1400);
                        return;

                    case 0xd002:
                    case 0xd040:
                        this.regs[4] = (this.regs[4] & 15) | ((value_Renamed & 15) << 4);
                        this.load1kVromBank(this.regs[4], 0x1000);
                        return;
                }
                return;
            }
            if (num <= 0xf004)
            {
                if (num != 0xe080)
                {
                    switch (num)
                    {
                        case 0xf000:
                            this.irq_latch = (this.irq_latch & 240) | (value_Renamed & 15);
                            return;

                        case 0xf001:
                            return;

                        case 0xf002:
                            goto Label_058B;

                        case 0xf003:
                            goto Label_05A2;

                        case 0xf004:
                            goto Label_05B3;

                        case 0xe0c0:
                            goto Label_0545;
                    }
                    return;
                }
                goto Label_0516;
            }
            switch (num)
            {
                case 0xf040:
                    goto Label_058B;

                case 0xf080:
                    goto Label_05B3;

                case 0xf0c0:
                    goto Label_05A2;

                default:
                    return;
            }
        }
    Label_02E8:
        this.regs[1] = (this.regs[1] & 240) | (value_Renamed & 15);
        this.load1kVromBank(this.regs[1], 0x400);
        return;
    Label_0317:
        this.regs[1] = (this.regs[1] & 15) | ((value_Renamed & 15) << 4);
        this.load1kVromBank(this.regs[1], 0x400);
        return;
    Label_0374:
        this.regs[2] = (this.regs[2] & 15) | ((value_Renamed & 15) << 4);
        this.load1kVromBank(this.regs[2], 0x800);
        return;
    Label_03A2:
        this.regs[3] = (this.regs[3] & 240) | (value_Renamed & 15);
        this.load1kVromBank(this.regs[3], 0xc00);
        return;
    Label_03D1:
        this.regs[3] = (this.regs[3] & 15) | ((value_Renamed & 15) << 4);
        this.load1kVromBank(this.regs[3], 0xc00);
        return;
    Label_0516:
        this.regs[7] = (this.regs[7] & 240) | (value_Renamed & 15);
        this.load1kVromBank(this.regs[7], 0x1c00);
        return;
    Label_0545:
        this.regs[7] = (this.regs[7] & 15) | ((value_Renamed & 15) << 4);
        this.load1kVromBank(this.regs[7], 0x1c00);
        return;
    Label_058B:
        this.irq_latch = (this.irq_latch & 15) | ((value_Renamed & 15) << 4);
        return;
    Label_05A2:
        this.irq_enabled = (this.irq_enabled & 1) * 3;
        return;
    Label_05B3:
        this.irq_enabled = value_Renamed & 3;
        if ((this.irq_enabled & 2) != 0)
        {
            this.irq_counter = this.irq_latch;
        }
    }
}

